home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BCI NET
/
BCI NET Dec 94.iso
/
archives
/
programming
/
source
/
fbm12s.lha
/
fltga.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-18
|
18KB
|
549 lines
/*****************************************************************
* fltga.c: FBM Release 1.0 25-Feb-90 Ian MacPhedran
*
* Author Ian MacPhedran.
* Permission is given to use any portion of this file, (including
* its entirety) for whatever you wish. Howvever, please note that
* it was written for Michael Mauldin's FBM Library, and conditions
* therein are more restrictive.
*
* FBM is Copyright (C) 1989,1990 by Michael Mauldin. Permission
* is granted to use this file in whole or in part for any purpose,
* educational, recreational or commercial, provided that this
* copyright notice is retained unchanged. This software is
* available to all free of charge by anonymous FTP and in the
* UUNET archives.
*
* CONTENTS
* read_tga (image, rfile, mstr, mlen)
* write_tga (image, wfile)
*
* HISTORY
* 25-Jun-90 Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
* Package for Release 1.0
*
* 13-Mar-89 Ian J. MacPhedran
* Add write_tga
*
* 07-Mar-89 Ian J. MacPhedran, University of Saskatchewan.
* Created.
*****************************************************************/
#include <stdio.h>
#include "fbm.h"
#ifndef lint
static char *fbmid =
"$FBM fltga.c <1.0> 25-Jun-90 by Ian MacPhedran, source code available \
free from MLM@CS.CMU.EDU and from UUNET archives$";
#endif
/* For convenience, the TGA header file is included herein. */
/*
* Header file for Targa file definitions.
*
* These definitions will allow a consistant interface to build Targa (.TGA)
* image files.
*
* Created NOV-15-1988 IJMP
*
*/
/* File header definition */
struct TGA_ImageHeader {
unsigned char IDLength;/* Length of Identifier String */
unsigned char CoMapType; /* 0 = NoMap */
unsigned char ImgType; /* Image Type (1,2,3,9,10) */
unsigned char Index_lo, Index_hi;
/* Index of first colour map entry */
unsigned char Length_lo, Length_hi;
/* Length of colour map (number of entries) */
unsigned char CoSize; /* Length of colour map entry */
unsigned char X_org_lo, X_org_hi; /* X Origin of Image */
unsigned char Y_org_lo, Y_org_hi; /* Y Origin of Image */
unsigned char Width_lo, Width_hi; /* Width of Image */
unsigned char Height_lo, Height_hi; /* Height of Image */
unsigned char PixelSize; /* Pixel Size (8,16,24) */
unsigned AttBits : 4; /* Number of Attribute Bits per pixel */
unsigned Rsrvd : 1; /* Reserved bit */
unsigned OrgBit : 1;
/* Origin Bit (0=lower left, 1=upper left) */
unsigned IntrLve : 2; /* Interleaving Flag */
};
char TGA_ImageIDField[256];
/* Definitions for Image Types */
#define TGA_MapRGBType 1
#define TGA_RawRGBType 2
#define TGA_RawMonoType 3
#define TGA_MapEnCodeType 9
#define TGA_RawEnCodeType 10
/*
* read_tga(image, rfile, mstr, mlen)
* from tga2rast.c:
* Version 1.0 - first released for public consumption, 21 Feb, 1989
*
*/
#define MAXCOLOURS 16384
/* Define flags for mode - these indicate special conditions */
#define GREYSC 0
#define COLOUR 1
#define MAPPED 2
#define RLENCD 4
#define INTERL 8
#define FOURWY 16
unsigned char ColourMap[MAXCOLOURS][3];
int RLE_count=0,RLE_flag=0;
read_tga(image, rfile, mstr, mlen)
FBM *image;
FILE *rfile;
char *mstr;
int mlen;
{
/* Define Identifiers */
struct TGA_ImageHeader *tga;
int i, j, l;
unsigned int temp1, temp2, mode;
unsigned char r, g, b;
unsigned long k, baseline,linewidth;
unsigned char *Red, *Grn, *Blu, *Redk, *Grnk, *Bluk;
/* Input the Targa file header */
if ((tga=(struct TGA_ImageHeader *)
malloc(sizeof(struct TGA_ImageHeader))) == NULL)
{
fprintf(stderr,"Can't allocate TGA memory\n");
exit(1);
}
if ((i = fread(tga,1,18,rfile)) != 18)
{
fprintf(stderr,"Read only %d bytes in header\n",i);
exit(1);
}
switch (tga->ImgType)
{
case TGA_MapRGBType:
case TGA_RawRGBType:
case TGA_RawMonoType:
case TGA_MapEnCodeType:
case TGA_RawEnCodeType:
break;
default:
fprintf(stderr,"Targa File Type %d",tga->ImgType);
fprintf(stderr," not supported!\n");
exit(1);
}
/* Create output image header */
temp1 = tga->Height_lo; temp2 = tga->Height_hi;
image->hdr.rows = temp1 + temp2 * 256;
temp1 = tga->Width_lo; temp2 = tga->Width_hi;
image->hdr.cols = temp1 + temp2 * 256;
/* If this is odd number of bytes, add one */
if ((image->hdr.cols & 1) != 0) image->hdr.cols++;
/* If greyscale, use only one plane */
if (tga->ImgType == TGA_RawMonoType)
{
image->hdr.planes = 1;
mode = GREYSC;
}
else
{
image->hdr.planes = 3;
mode = COLOUR;
}
/* Uses 8 bits, sort of - 16 bits/pixel is 5 bits per colour */
image->hdr.bits = 8;
image->hdr.physbits = 8;
image->hdr.rowlen = image->hdr.cols;
image->hdr.plnlen = image->hdr.rows * image->hdr.cols;
/* Ignore colour map for this version. */
image->hdr.clrlen = 0;
image->hdr.aspect = 1.0;
image->hdr.title[0] = '\0';
image->hdr.credits[0] = '\0';
/* Get the Image */
alloc_fbm(image);
/* Read ID String, if present */
if (tga->IDLength != 0)
fread(TGA_ImageIDField,1,tga->IDLength,rfile);
/* If present, read the colour map information */
if (tga->CoMapType != 0)
{
temp1 = tga->Index_lo + tga->Index_hi * 256;
temp2 = tga->Length_lo + tga->Length_hi * 256;
if ((temp1+temp2+1) >= MAXCOLOURS)
{
fprintf(stderr,"Too many colours %d\n",(temp1+temp2+1));
exit(1);
}
for (i=temp1; i<(temp1+temp2); i++)
get_map_entry(&ColourMap[i][0],&ColourMap[i][1],
&ColourMap[i][2],tga->CoSize,mode);
if ((tga->ImgType != TGA_RawRGBType) &&
(tga->ImgType != TGA_RawMonoType) &&
(tga->ImgType != TGA_RawEnCodeType))
mode = mode | MAPPED;
}
/* Check Run Length Encoding */
if ((tga->ImgType == TGA_MapEnCodeType) ||
(tga->ImgType == TGA_RawEnCodeType))
mode = mode | RLENCD;
/* Check for interlacing of the Targa file */
switch (tga->IntrLve)
{
case 2: /* Four way interlace */
mode = mode | FOURWY;
case 1: /* Two way interlace */
mode = mode | INTERL;
case 0: /* No interlace */
break;
default: /* Reserved - we'll let it pass */
break;
}
/* Set up byte map for writing */
Red = image->bm;
if ((mode & COLOUR) != GREYSC)
{
Grn = Red + image->hdr.plnlen;
Blu = Grn + image->hdr.plnlen;
}
/* Read the Targa file body and convert to image format */
linewidth = tga->Width_lo + tga->Width_hi * 256;
for (i=0; i< image->hdr.rows; i++)
{
/* No interlace */
if ((mode & INTERL) == 0)
{
j = i;
}
/* Two way interlace */
else if ((mode & FOURWY) != 0)
{
if (2*i < image->hdr.rows)
j = 2*i;
else
{
j = i - image->hdr.rows/2;
j = 2*j + 1;
}
}
/* Four way interlace */
else
{
if (4*i < image->hdr.rows)
j = 4*i;
else if (2*i < image->hdr.rows)
{
j = i - image->hdr.rows/4;
j = 4*j + 1;
}
else if (4*i < 3*image->hdr.rows)
{
j = i - image->hdr.rows/2;
j = 4*j + 2;
}
else
{
j = i - image->hdr.rows/2 - image->hdr.rows/4;
j = 4*j + 3;
}
}
k = (image->hdr.rows - 1 - j) * image->hdr.cols;
Redk = Red + k;
if ((mode & COLOUR) != GREYSC)
{
Grnk = Grn + k; Bluk = Blu + k;
}
for (j=0; j<linewidth; j++)
{
get_pixel(&r,&g,&b,tga->PixelSize,mode);
*Redk++=r;
if ((mode & COLOUR) != GREYSC)
{
*Grnk++=g; *Bluk++=b;
}
}
}
free(tga);
}
get_map_entry(Red,Grn,Blu,Size,mode)
unsigned char *Red,*Grn,*Blu;
int Size,mode;
{
unsigned int j,k,l,m;
unsigned char i,r,g,b;
/* read appropriate number of bytes, break into rgb & put in map */
switch (Size)
{
case 8: /* Grey Scale already, read and triplicate */
fread(&i,1,1,stdin);
r = i; g = i; b = i;
break;
case 16: /* 5 bits each of red green and blue */
case 15: /* Watch for byte order */
fread(&j,1,1,stdin);
fread(&k,1,1,stdin);
l = j + k*256;
r = ((l >> 10) & 31) << 3;
g = ((l >> 5) & 31) << 3;
b = (l & 31) << 3;
break;
case 32: /* Read alpha byte & throw away */
case 24: /* Eight bits each of red green and blue */
fread(&i,1,1,stdin); b = i;
fread(&i,1,1,stdin); g = i;
fread(&i,1,1,stdin); r = i;
if (Size == 32) fread(&i,1,1,stdin);
break;
default:
fprintf(stderr,"Unknown Pixel Size\n"); exit(1);
}
*Red = r; *Grn = g; *Blu = b;
}
get_pixel(rRed,rGrn,rBlu,Size,mode)
unsigned char *rRed,*rGrn,*rBlu;
int Size,mode;
{
static unsigned char Red, Grn, Blu;
unsigned char i,j,k;
static unsigned int l;
/* Check if run length encoded. */
if ((mode & RLENCD) != 0)
{
if (RLE_count == 0) /* Have to restart run */
{
fread(&i,1,1,stdin);
RLE_flag = (i & 0x80) >> 7;
if (RLE_flag == 0)
{ /* Stream of unencoded pixels */
RLE_count = i + 1;
}
else
{ /* Single pixel replicated */
RLE_count = i - 127;
}
RLE_count--; /* Decrement count & get pixel */
}
else
{ /* Have already read count & (at least) first pixel */
RLE_count--;
if (RLE_flag != 0)
{ /* Replicated pixels */
goto PixEncode;
}
}
}
/* Read appropriate number of bytes, break into RGB */
switch(Size)
{
case 8: /* Grey Scale - read a byte and triplicate */
fread(&i,1,1,stdin);
Red = i; Grn = i; Blu = i; l = i;
break;
case 16: /* Five bits each of red green and blue */
case 15: /* Watch byte order */
fread(&j,1,1,stdin);
fread(&k,1,1,stdin);
l = j + k*256;
Red = ((k & 0x7C) << 1);
Grn = ((k & 0x03) << 6) + ((j & 0xE0) >> 2);
Blu = ((j & 0x1F) << 3);
break;
case 32: /* Read alpha byte & throw away */
case 24: /* Eight bits each of red green and blue */
fread(&i,1,1,stdin); Blu = i;
fread(&i,1,1,stdin); Grn = i;
fread(&i,1,1,stdin); Red = i;
if (Size == 32) fread(&i,1,1,stdin);
l = 0;
break;
default:
fprintf(stderr,"Unknown Pixel Size\n"); exit(1);
}
PixEncode:
if ((mode & MAPPED) == MAPPED)
{
*rRed = ColourMap[l][0];
*rGrn = ColourMap[l][1];
*rBlu = ColourMap[l][2];
}
else
{
*rRed = Red;
*rGrn = Grn;
*rBlu = Blu;
}
}
/*
* write_tga(image, wfile)
*
*/
write_tga(image, wfile)
FBM *image;
FILE *wfile;
{
unsigned char *Red, *Grn, *Blu, *Redk, *Grnk, *Bluk;
unsigned char *Redc, *Grnc, *Bluc, *Redck, *Grnck, *Bluck;
struct TGA_ImageHeader *tga;
unsigned char buffer[MAXCOLOURS];
unsigned int mode;
unsigned long index, index2;
int i, j, k, l;
if (image->hdr.cols > (MAXCOLOURS / 2))
{
fprintf(stderr,"Line too wide is %d, must be %d\n",
image->hdr.cols, MAXCOLOURS/2);
exit(1);
}
if ((image->hdr.planes != 1) && (image->hdr.planes != 3))
{
fprintf(stderr,"TGA files must 1 or 3 planes deep\n");
exit(1);
}
if (image->hdr.planes == 1) mode = GREYSC;
else mode = COLOUR;
if ((tga=(struct TGA_ImageHeader *)
malloc(sizeof(struct TGA_ImageHeader))) == NULL)
{
fprintf(stderr,"Can't allocate TGA memory\n");
exit(1);
}
tga->IDLength = 0; /* Don't write ID into file */
tga->CoMapType = 0; /* Use raw bytes, not mapped */
tga->ImgType = TGA_RawRGBType;
if ((mode & COLOUR) == GREYSC) tga->ImgType = TGA_RawMonoType;
tga->Index_hi = 0; tga->Index_lo = 0; /* Colour Mapped stuff */
tga->Length_hi = 0; tga->Length_lo = 0;
tga->CoSize = 8;
tga->X_org_lo = 0; tga->X_org_hi = 0; /* Origin at 0,0 */
tga->Y_org_lo = 0; tga->Y_org_hi = 0;
tga->Width_hi = (unsigned char)(image->hdr.cols / 256);
tga->Width_lo = (unsigned char)(image->hdr.cols % 256);
tga->Height_hi = (unsigned char)(image->hdr.rows / 256);
tga->Height_lo = (unsigned char)(image->hdr.rows % 256);
tga->PixelSize = 16;
if ((mode & COLOUR) == GREYSC) tga->PixelSize = 8;
/* All funny bits set to zero */
tga->AttBits = 0; tga->Rsrvd = 0; tga->OrgBit = 0; tga->IntrLve = 0;
fwrite(tga,1,18,wfile); /* Write out header */
Red = image->bm;
l = image->hdr.cols;
if ((mode & COLOUR) == COLOUR)
{
l = l * 2;
Grn = Red + image->hdr.plnlen;
Blu = Grn + image->hdr.plnlen;
}
if (image->hdr.clrlen > 0)
{
mode = mode | MAPPED;
Redc = image->cm;
if ((mode & COLOUR) == COLOUR)
{
Grnc = Redc + image->hdr.clrlen/3;
Bluc = Grnc + image->hdr.clrlen/3;
}
}
Redk = Red + image->hdr.plnlen - image->hdr.cols;
if ((mode & COLOUR) == COLOUR)
{
Grnk = Grn + image->hdr.plnlen - image->hdr.cols;
Bluk = Blu + image->hdr.plnlen - image->hdr.cols;
}
/* Okay, ready to write */
for (j=0; j<image->hdr.rows; j++)
{
for (i=0; i<image->hdr.cols; i++)
{
index = *Redk++;
if ((mode & COLOUR) == COLOUR)
index = (index << 16) + ((*Grnk++) << 8) + *Bluk++;
if ((mode & MAPPED) == MAPPED)
{
index2 = index;
Redck = Redc + index2;
index = *Redck;
if ((mode & COLOUR) == COLOUR)
{
Grnck = Grnc + index2; Bluck = Bluc + index2;
index = (index << 16) +
((unsigned long)*Grnck << 8) +
*Bluck;
}
}
if ((mode & COLOUR) == COLOUR)
{
index2 = ((index & 0x00f80000) >> 9)
+ ((index & 0x0000f800) >> 6)
+ ((index & 0x000000f8) >> 3);
k = 2 * i;
buffer[k] = (unsigned char)(index2 % 256);
k = k + 1;
buffer[k] = (unsigned char)(index2 / 256);
}
else
{
buffer[i] = (unsigned char)index;
}
}
fwrite(buffer,l,1,wfile);
Redk = Redk - 2 * image->hdr.cols;
if ((mode & COLOUR) == COLOUR)
{
Grnk = Grnk - 2 * image->hdr.cols;
Bluk = Bluk - 2 * image->hdr.cols;
}
}
free(tga);
}